#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <ctype.h>
#include <fcntl.h>

#define LINE_SIZE 1024
#define SPLIT_SIZE 32
#define LEFT "["
#define RIGHT "]"
#define DELIM " \t"
#define LABLE "#"
#define EXIT_CODE 11
#define IN_RDIR 0
#define OUT_RDIR 1
#define APPEND_RDIR 2
#define NONE -1

char myenv[LINE_SIZE];
int lastcode = 0;
char pwd[LINE_SIZE];
int rdir = NONE;
char* pfd = NULL;


void check_rdir(char* cmd){
    char* pos = cmd;
    while(*pos){
        if(*pos == '>'){
            if(*(pos+1) == '>'){
                *pos++ = '\0';
                *pos++ = '\0';
                while(isspace(*pos)) pos++;
                pfd = pos;
                rdir = APPEND_RDIR;
                break;
            }
            else{
                *pos++ = '\0';
                while(isspace(*pos)) pos++;
                pfd = pos;
                rdir = OUT_RDIR;
                break;
            }
        }
        else if(*pos == '<'){
            *pos++ = '\0';
            while(isspace(*pos)) pos++;
            pfd = pos;
            rdir = IN_RDIR;
            break;
        }
        else{
            pos++;
        }
    }
}


void interact(char* cline,int size){
    char* s = fgets(cline,size,stdin);
    assert(s);
    (void)s;
    cline[strlen(cline)-1] = '\0';
    check_rdir(cline);
}

void getpwd()
{
    getcwd(pwd,sizeof(pwd));
}

int Splitstring(char* argv[],char* command){
    int i = 0;
    argv[i++] = strtok(command,DELIM);
    while(argv[i++] = strtok(NULL,DELIM));
    return i - 1;
}

void NormalExcute(char* argv[]){
    pid_t id = fork();
    if(id < 0){
        perror("fork:\n");
        return;
    }
    else if(id == 0){
        int fd = 0;
        if(rdir == IN_RDIR){
            fd = open(pfd,O_RDONLY);
            dup2(fd,0);
        }
        else if(rdir == OUT_RDIR){
            fd = open(pfd,O_WRONLY|O_TRUNC|O_CREAT,0666);
            dup2(fd,1);
        }
        else if(rdir == APPEND_RDIR){
            fd = open(pfd,O_WRONLY|O_APPEND|O_CREAT,0666);
            dup2(fd,1);
        }
        execvp(argv[0],argv);
        exit(EXIT_CODE);
    }
    else{
        int status = 0;
        pid_t ret = waitpid(id,&status,0);
        lastcode = WEXITSTATUS(status);
        if(ret == id) {}
        else{
            printf("exit_code : %d\n",WEXITSTATUS(status));
            return;
        }
    }
}

int buildcommand(char* argv[],int argc){
    if(argc == 2 && strcmp(argv[0],"cd") == 0){
        chdir(argv[1]);
        getpwd();
        sprintf(getenv("PWD"),"%s",pwd);
        return 1;
    }
    else if(argc == 2 && strcmp(argv[0],"export") == 0){
        strcpy(myenv,argv[1]);
        putenv(myenv);
        return 1;
    }
    else if(strcmp(argv[0],"echo") == 0){
        if(strcmp(argv[1],"$?") == 0){
            printf("%d\n",lastcode);
            lastcode = 0;
        }
        else if(argv[1][0] == '$'){
            char *tmp = argv[1] + 1;
            if(tmp != NULL)
                printf("%s\n",getenv(tmp));
        }
        else{
            printf("%s\n",argv[1]);
        }
        return 1;
    }
    if(strcmp(argv[0],"ls") == 0){
        argv[argc++] = "--color";
        argv[argc] = NULL;
    }
    return 0;
}

// int main()
// {
//     char command[LINE_SIZE];
//     char* argv[SPLIT_SIZE];
//     while(1){
//         rdir = NONE;
//         pfd = NULL;
//         getpwd();
//         printf(LEFT"%s@%s %s" RIGHT "" LABLE " ",getenv("USER"),getenv("HOSTNAME"),pwd);
//         interact(command,sizeof(command));
//         //command[strlen(command) - 1] = '\0'; 

//         int argc = Splitstring(argv,command);
//         int flag = buildcommand(argv,argc);

//         if(!flag)NormalExcute(argv);
//         //for(int i = 0;argv[i];i++){
//         //    printf("[%d] : %s\n",i,argv[i]);
//         //}
//     }
//     return 0;
// }

#define MAX_COMMAND_LENGTH 2048
#define MAX_COMMANDS 10

// 分割命令行字符串为多个子命令
// void split_commands(char *command, char *commands[MAX_COMMANDS]) {
//     char *token = strtok(command, "|");
//     int i = 0;
//     while (token != NULL && i < MAX_COMMANDS) {
//         commands[i] = token;
//         token = strtok(NULL, "|");
//         i++;
//     }
//     commands[i] = NULL;
// }

// int main() {
//     char command[MAX_COMMAND_LENGTH];
//     char *commands[MAX_COMMANDS];
//     int num_commands = 0;
//     int pipes[MAX_COMMANDS - 1][2];  // 存储管道的文件描述符
//     char* argv[LINE_SIZE];

//     // 读取用户输入的命令行
//     printf("请输入命令: ");
//     fgets(command, MAX_COMMAND_LENGTH, stdin);
//     command[strcspn(command, "\n")] = 0;  // 去除换行符

//     // 分割命令
//     split_commands(command, commands);
//     // int j = 0;
//     // while(commands[j]){
//     //     Splitstring(argv,commands[j++]);
//     // }

//     // 统计子命令的数量
//     while (commands[num_commands] != NULL) {
//         num_commands++;
//     }

//     // 创建管道
//     for (int i = 0; i < num_commands - 1; i++) {
//         if (pipe(pipes[i]) == -1) {
//             perror("pipe");
//             exit(EXIT_FAILURE);
//         }
//     }

//     for (int i = 0; i < num_commands; i++) {
//         pid_t pid = fork();
//         if (pid == -1) {
//             perror("fork");
//             exit(EXIT_FAILURE);
//         } else if (pid == 0) {  // 子进程
//             // 重定向输入输出
//             if (i > 0) {
//                 dup2(pipes[i - 1][0], 0);  // 标准输入重定向到上一个管道的读端
//                 close(pipes[i - 1][0]);
//                 close(pipes[i - 1][1]);
//             }
//             if (i < num_commands - 1) {
//                 dup2(pipes[i][1], 1);  // 标准输出重定向到下一个管道的写端
//                 close(pipes[i][0]);
//                 close(pipes[i][1]);
//             }

//             // 执行命令
//             char *args[MAX_COMMAND_LENGTH / 2];
//             char *token = strtok(commands[i], " ");
//             int j = 0;
//             while (token != NULL) {
//                 args[j] = token;
//                 token = strtok(NULL, " ");
//                 j++;
//             }
//             args[j] = NULL;

//             if (execvp(args[0], args) == -1) {
//                 perror("execvp");
//                 exit(EXIT_FAILURE);
//             }
//         } else {  // 父进程
//             // 关闭不需要的管道文件描述符
//             if (i > 0) {
//                 close(pipes[i - 1][0]);
//                 close(pipes[i - 1][1]);
//             }
//             if (i < num_commands - 1) {
//                 close(pipes[i][0]);
//                 close(pipes[i][1]);
//             }
//         }
//     }

//     // 等待所有子进程结束
//     for (int i = 0; i < num_commands; i++) {
//         wait(NULL);
//     }

//     return 0;
// }

char buffer[MAX_COMMAND_LENGTH];
// 分割命令行字符串为多个子命令
void split_commands(char *command, char *commands[MAX_COMMANDS]) {
    char *token = strtok(command, "|");
    int i = 0;
    while (token != NULL && i < MAX_COMMANDS) {
        commands[i] = token;
        token = strtok(NULL, "|");
        i++;
    }
    commands[i] = NULL;
}

// 解析单个子命令的参数
void parse_arguments(char *sub_command, char *args[MAX_COMMAND_LENGTH / 2]) {
    char *token = strtok(sub_command, " ");
    int i = 0;
    while (token != NULL) {
        args[i] = token;
        token = strtok(NULL, " ");
        i++;
    }
    args[i] = NULL;
}

void writer(int wfd){
    int cnt = 10;
    buffer[0] = 0;
    // cout << buffer << endl;
    write(wfd,buffer,strlen(buffer));
}

void reader(int rfd){
    int time = 0;
    buffer[0] = '\0';
    int n = read(rfd,buffer,sizeof(buffer));
}


int main() {
    char command[MAX_COMMAND_LENGTH];
    char *commands[MAX_COMMANDS];
    int num_commands = 0;
    int pipes[MAX_COMMANDS - 1][2];  // 存储管道的文件描述符

    // 读取用户输入的命令行
    printf("请输入命令(支持管道操作,例如ls -l | grep.txt): ");
    if (fgets(command, MAX_COMMAND_LENGTH, stdin) == NULL) {
        perror("fgets");
        return EXIT_FAILURE;
    }
    // 去除换行符
    command[strcspn(command, "\n")] = 0;

    // 分割命令
    split_commands(command, commands);
    printf("%d\n",num_commands);
    // 统计子命令的数量
    while (commands[num_commands] != NULL) {
        num_commands++;
    }
    printf("%d\n",num_commands);
    // 创建管道
    for (int i = 0; i < num_commands - 1; i++) {
        if (pipe(pipes[i]) == -1) {
            perror("pipe");
            return EXIT_FAILURE;
        }
        printf("%d  %d\n",pipes[i][0],pipes[i][1]);
    }

    for (int i = 0; i < num_commands; i++) {
        pid_t id = fork();
        if (id == -1) {
            perror("fork");
            return EXIT_FAILURE;
        } else if (id == 0) {  // 子进程
            // 重定向输入输出
            if (i > 0) {
                if (dup2(pipes[i - 1][0], 0) == -1) {
                    perror("dup2 input");
                    _exit(EXIT_FAILURE);
                }
                // close(pipes[i - 1][0]);
                // close(pipes[i - 1][1]);
            }
            if (i < num_commands - 1) {
                if (dup2(pipes[i][1], 1) == -1) {
                    perror("dup2 output");
                    _exit(EXIT_FAILURE);
                }
                // close(pipes[i][0]);
                // close(pipes[i][1]);
            }
            // reader(pipes[i][0]);
            // writer(pipes[i][1]);
            // 解析子命令的参数
            char *args[MAX_COMMAND_LENGTH / 2];
            parse_arguments(commands[i], args);

            // 执行命令
            if (execvp(args[0], args) == -1) {
                perror("execvp");
                // 打印尝试执行的命令及其参数，便于调试
                printf("尝试执行的命令: %s", args[0]);
                for (int j = 1; args[j] != NULL; j++) {
                    printf(" %s", args[j]);
                }
                printf("\n");
                exit(EXIT_FAILURE);
            }
            //exit(0);
        } else {  // 父进程
            //等待子进程
            if(i < num_commands - 1) close(pipes[i][1]);
            waitpid(id,NULL,0);
            if(i > 0) close(pipes[i-1][0]);
        }
    }
    return 0;
}